home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.0 / stk-3 / blt-for-STk-3.0 / blt-1.9 / src / bltGrLine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-01  |  41.8 KB  |  1,421 lines

  1.  
  2. /*
  3.  * bltGrLine.c --
  4.  *
  5.  *    This module implements line elements in the graph widget
  6.  *    for the Tk toolkit.
  7.  *
  8.  * Copyright 1991-1994 by AT&T Bell Laboratories.
  9.  * Permission to use, copy, modify, and distribute this software
  10.  * and its documentation for any purpose and without fee is hereby
  11.  * granted, provided that the above copyright notice appear in all
  12.  * copies and that both that the copyright notice and warranty
  13.  * disclaimer appear in supporting documentation, and that the
  14.  * names of AT&T Bell Laboratories any of their entities not be used
  15.  * in advertising or publicity pertaining to distribution of the
  16.  * software without specific, written prior permission.
  17.  *
  18.  * AT&T disclaims all warranties with regard to this software, including
  19.  * all implied warranties of merchantability and fitness.  In no event
  20.  * shall AT&T be liable for any special, indirect or consequential
  21.  * damages or any damages whatsoever resulting from loss of use, data
  22.  * or profits, whether in an action of contract, negligence or other
  23.  * tortuous action, arising out of or in connection with the use or
  24.  * performance of this software.
  25.  *
  26.  */
  27.  
  28. #include "blt.h"
  29. #include "bltGraph.h"
  30. #include <ctype.h>
  31. #include <X11/Xutil.h>
  32. #include <X11/Xatom.h>
  33.  
  34.  
  35. /*
  36.  * Sun's bundled and unbundled C compilers can't grok static function
  37.  * typedefs (it can handle extern) like
  38.  *
  39.  *     static Tk_OptionParseProc parseProc;
  40.  *      static Tk_OptionPrintProc printProc;
  41.  *
  42.  * Provide forward declarations here:
  43. */
  44. static int ParseSymbolType _ANSI_ARGS_((ClientData clientData,
  45.     Tcl_Interp *interp, Tk_Window tkwin, char *value, char *widgRec,
  46.     int offset));
  47. static char *PrintSymbolType _ANSI_ARGS_((ClientData clientData,
  48.     Tk_Window tkwin, char *widgRec, int offset,
  49.     Tcl_FreeProc **freeProcPtr));
  50.  
  51. static int ParseTrace _ANSI_ARGS_((ClientData clientData,
  52.     Tcl_Interp *interp, Tk_Window tkwin, char *value, char *widgRec,
  53.     int offset));
  54. static char *PrintTrace _ANSI_ARGS_((ClientData clientData,
  55.     Tk_Window tkwin, char *widgRec, int offset,
  56.     Tcl_FreeProc **freeProcPtr));
  57.  
  58. #include "bltGrElem.h"
  59.  
  60. /*
  61.  * Element attributes: either symbol types or line styles
  62. */
  63. static char *symbolTokens[] =
  64. {
  65.     "Line", "Square", "Circle",
  66.     "Diamond", "Plus", "Cross",
  67.     "Splus", "Scross", (char *)NULL,
  68. };
  69.  
  70. #define TRACE_BOTH         0
  71. #define TRACE_INCREASING    1
  72. #define TRACE_DECREASING    2
  73. #define BROKEN_TRACE(dir,x,last) \
  74.     ((((dir) != TRACE_DECREASING) && ((x) < (last))) || \
  75.      (((dir) != TRACE_INCREASING) && ((x) > (last))))
  76.  
  77. /*
  78.  * Trace option values
  79.  */
  80. static char *traceTokens[] =
  81. {
  82.     "both", "increasing", "decreasing", (char *)NULL,
  83. };
  84.  
  85. typedef struct {
  86.     SymbolType type;
  87.     Display *display;        /* Display on which to draw symbol */
  88.     Drawable canvas;        /* Window to draw symbol */
  89.     GC lineGC;
  90.     GC borderGC;
  91.     GC fillGC;
  92.     int radius;
  93.     int size;
  94.     int needBorder;
  95.     XPoint offset[13];
  96.  
  97. } SymbolInfo;
  98.  
  99.  
  100. typedef struct {
  101.     XPoint *pointPtr;        /* Array of points defining the segment */
  102.     int numPoints;        /* Number of points in segment */
  103. } CurveSegment;
  104.  
  105. typedef struct {
  106.     Tcl_Interp *interp;        /* Interpreter of the graph widget.
  107.                  * This is only needed for
  108.                  * Tcl_PrintDouble calls in the custom
  109.                  * configure print routines. */
  110.     ElementClassType type;    /* Type of element is LINE_ELEMENT */
  111.     unsigned int flags;
  112.     Tk_Uid id;            /* Identifier to refer the element.
  113.                  * Used in the "insert", "delete", or
  114.                  * "show", commands. */
  115.     int mapped;            /* If non-zero, element is currently
  116.                  * visible.*/
  117.     Tk_ConfigSpec *configSpecs;    /* Configuration specifications */
  118.     char *label;        /* Label displayed in legend */
  119.     SymbolType symbol;        /* Element symbol type */
  120.     double symbolScale;        /* Scale factor when computing symbol
  121.                  * size */
  122.     unsigned int symbolSize;    /* Computed size of symbol in pixels. */
  123.     Vector x, y;        /* Contains array of numeric values */
  124.     unsigned int axisFlags;    /* Indicates which axes to map element's
  125.                  * coordinates onto */
  126.     int *activeArr;        /* Array of indices of active data
  127.                  * points (malloc-ed). Initially points
  128.                  * to static storage "staticArr". */
  129.     int staticArr[DEF_ACTIVE_SIZE];
  130.     int numActivePoints;    /* Number of active data points. If
  131.                  * zero and active bit is set in
  132.                  * "flags", then all data points are
  133.                  * active. */
  134.  
  135.     ElemConfigProc *configProc;
  136.     ElemDestroyProc *destroyProc;
  137.     ElemDisplayProc *displayProc;
  138.     ElemLimitsProc *limitsProc;
  139.     ElemDistanceProc *closestProc;
  140.     ElemLayoutProc *layoutProc;
  141.     ElemPrintProc *printProc;
  142.     ElemDrawSymbolsProc *drawSymbolsProc;
  143.     ElemPrintSymbolsProc *printSymbolsProc;
  144.  
  145.     /*
  146.      * Line specific configurable attributes
  147.      */
  148.     XColor *normalFg;        /* normal color of lines/borders*/
  149.     XColor *normalBg;        /* normal color of dashed lines, fills */
  150.     XColor *activeFg;        /* active color of lines/borders */
  151.     XColor *activeBg;        /* active color of dashed lines, fills */
  152.  
  153.     int lineWidth;        /* Width of the line connecting the
  154.                  * symbols together. If less than 0,
  155.                  * no line is drawn. */
  156.     int activeLineWidth;    /* Width of the active line */
  157.     int borderWidth;        /* Width of the border around the
  158.                    symbol */
  159.     int dashes;            /* Dash on-off list value */
  160.     int trace;            /* Indicates if to break connected line
  161.                  * segments where x-coordinate values
  162.                  * are not monotonically increasing or
  163.                  * decreasing. */
  164.     GC normalBorderGC;        /* Symbol border graphics context */
  165.     GC normalFillGC;        /* Symbol fill graphics context */
  166.     GC normalLineGC;        /* Line graphics context */
  167.  
  168.     GC activeLineGC;
  169.     GC activeFillGC;
  170.     GC activeBorderGC;
  171.     /*
  172.      * Drawing related structures
  173.      */
  174.     XPoint *pointArr;        /* Array of window coordinates
  175.                  * representing the points of the line
  176.                  * (malloc'ed) */
  177.     int numPoints;        /* Number of points in point array */
  178.     CurveSegment *segArr;    /* Array of line segment information
  179.                  * (malloc'ed) */
  180.     int numSegments;        /* Number of line segments in point
  181.                  * array */
  182.  
  183. } Line;
  184.  
  185. extern Tk_CustomOption bltXVectorOption;
  186. extern Tk_CustomOption bltYVectorOption;
  187. extern Tk_CustomOption bltTwinOption;
  188. extern Tk_CustomOption bltXAxisFlagsOption;
  189. extern Tk_CustomOption bltYAxisFlagsOption;
  190.  
  191. static Tk_CustomOption SymbolOption =
  192. {
  193.     ParseSymbolType, PrintSymbolType, (ClientData)0
  194. };
  195.  
  196. static Tk_CustomOption TraceOption =
  197. {
  198.     ParseTrace, PrintTrace, (ClientData)0
  199. };
  200.  
  201. #define DEF_LINE_ACTIVE_BG_COLOR "red"
  202. #define DEF_LINE_ACTIVE_BG_MONO    WHITE
  203. #define DEF_LINE_ACTIVE_FG_COLOR "pink"
  204. #define DEF_LINE_ACTIVE_FG_MONO BLACK
  205. #define DEF_LINE_ACTIVE_LINE_WIDTH "1"
  206. #define DEF_LINE_BG_COLOR    "navyblue"
  207. #define DEF_LINE_BG_MONO    BLACK
  208. #define DEF_LINE_DASHES        "0"
  209. #define DEF_LINE_DATA        (char *)NULL
  210. #define DEF_LINE_FG_COLOR         "blue"
  211. #define DEF_LINE_FG_MONO    WHITE
  212. #define DEF_LINE_LABEL        (char *)NULL
  213. #define DEF_LINE_SYMBOL_BW     "1"
  214. #define DEF_LINE_SYMBOL_SCALE    "1.0"
  215. #define DEF_LINE_TRACE        "both"
  216. #define DEF_LINE_WIDTH         "1"
  217. #define DEF_LINE_X_AXIS        "x"
  218. #define DEF_LINE_X_DATA        (char *)NULL
  219. #define DEF_LINE_Y_AXIS        "y"
  220. #define DEF_LINE_Y_DATA        (char *)NULL
  221. #define DEF_LINE_SYMBOL        "line"
  222.  
  223. static Tk_ConfigSpec configSpecs[] =
  224. {
  225.     {TK_CONFIG_COLOR, "-activebackground",
  226.     "elemActiveBackground", "Background",
  227.     DEF_LINE_ACTIVE_BG_COLOR, Tk_Offset(Line, activeBg),
  228.     TK_CONFIG_COLOR_ONLY},
  229.     {TK_CONFIG_COLOR, "-activebackground",
  230.     "elemActiveBackground", "Background",
  231.     DEF_LINE_ACTIVE_BG_MONO, Tk_Offset(Line, activeBg),
  232.     TK_CONFIG_MONO_ONLY},
  233.     {TK_CONFIG_COLOR, "-activeforeground",
  234.     "elemActiveForeground", "Foreground",
  235.     DEF_LINE_ACTIVE_FG_COLOR, Tk_Offset(Line, activeFg),
  236.     TK_CONFIG_COLOR_ONLY},
  237.     {TK_CONFIG_COLOR, "-activeforeground",
  238.     "elemActiveForeground", "Foreground",
  239.     DEF_LINE_ACTIVE_FG_MONO, Tk_Offset(Line, activeFg),
  240.     TK_CONFIG_MONO_ONLY},
  241.     {TK_CONFIG_PIXELS, "-activelinewidth", "elemActiveLineWidth", "LineWidth",
  242.     DEF_LINE_ACTIVE_LINE_WIDTH, Tk_Offset(Line, activeLineWidth),
  243.     TK_CONFIG_DONT_SET_DEFAULT},
  244.     {TK_CONFIG_COLOR, "-background", "elemBackground", "Background",
  245.     DEF_LINE_BG_COLOR, Tk_Offset(Line, normalBg),
  246.     TK_CONFIG_COLOR_ONLY},
  247.     {TK_CONFIG_COLOR, "-background", "elemBackground", "Background",
  248.     DEF_LINE_BG_MONO, Tk_Offset(Line, normalBg),
  249.     TK_CONFIG_MONO_ONLY},
  250.     {TK_CONFIG_SYNONYM, "-bg", "elemBackground", (char *)NULL,
  251.     (char *)NULL, 0, 0},
  252.     {TK_CONFIG_PIXELS, "-borderwidth", "elemBorderWidth", "BorderWidth",
  253.     DEF_LINE_SYMBOL_BW, Tk_Offset(Line, borderWidth),
  254.     TK_CONFIG_DONT_SET_DEFAULT},
  255.     {TK_CONFIG_INT, "-dashes", "elemDashes", "Dashes",
  256.     DEF_LINE_DASHES, Tk_Offset(Line, dashes),
  257.     TK_CONFIG_DONT_SET_DEFAULT},
  258.     {TK_CONFIG_CUSTOM, "-data", "elemData", "Data",
  259.     DEF_LINE_DATA, 0, 0, &bltTwinOption},
  260.     {TK_CONFIG_SYNONYM, "-fg", "elemForeground", (char *)NULL,
  261.     (char *)NULL, 0, TK_CONFIG_COLOR_ONLY},
  262.     {TK_CONFIG_SYNONYM, "-fg", "elemForeground", (char *)NULL,
  263.     (char *)NULL, 0, 0},
  264.     {TK_CONFIG_COLOR, "-foreground", "elemForeground", "Foreground",
  265.     DEF_LINE_FG_COLOR, Tk_Offset(Line, normalFg),
  266.     TK_CONFIG_COLOR_ONLY},
  267.     {TK_CONFIG_COLOR, "-foreground", "elemForeground", "Foreground",
  268.     DEF_LINE_FG_MONO, Tk_Offset(Line, normalFg),
  269.     TK_CONFIG_MONO_ONLY},
  270.     {TK_CONFIG_STRING, "-label", "elemLabel", "Label",
  271.     DEF_LINE_LABEL, Tk_Offset(Line, label), TK_CONFIG_NULL_OK},
  272.     {TK_CONFIG_PIXELS, "-linewidth", "elemLineWidth", "LineWidth",
  273.     DEF_LINE_WIDTH, Tk_Offset(Line, lineWidth),
  274.     TK_CONFIG_DONT_SET_DEFAULT},
  275.     {TK_CONFIG_CUSTOM, "-mapx", "elemMapX", "MapX",
  276.     DEF_LINE_X_AXIS, Tk_Offset(Line, axisFlags),
  277.     TK_CONFIG_DONT_SET_DEFAULT, &bltXAxisFlagsOption},
  278.     {TK_CONFIG_CUSTOM, "-mapy", "elemMapY", "MapY",
  279.     DEF_LINE_Y_AXIS, Tk_Offset(Line, axisFlags),
  280.     TK_CONFIG_DONT_SET_DEFAULT, &bltYAxisFlagsOption},
  281.     {TK_CONFIG_BOOLEAN, "-noretrace", "elemNoretrace", "Noretrace",
  282.     (char *)NULL, Tk_Offset(Line, trace), 0},
  283.     {TK_CONFIG_DOUBLE, "-scale", "elemScale", "Scale",
  284.     DEF_LINE_SYMBOL_SCALE, Tk_Offset(Line, symbolScale),
  285.     TK_CONFIG_DONT_SET_DEFAULT},
  286.     {TK_CONFIG_CUSTOM, "-symbol", "elemSymbol", "Symbol",
  287.     DEF_LINE_SYMBOL, Tk_Offset(Line, symbol), 0, &SymbolOption},
  288.     {TK_CONFIG_CUSTOM, "-trace", "elemTrace", "Trace",
  289.     DEF_LINE_TRACE, Tk_Offset(Line, trace),
  290.     TK_CONFIG_DONT_SET_DEFAULT, &TraceOption},
  291.     {TK_CONFIG_CUSTOM, "-xdata", "elemXdata", "Xdata",
  292.     DEF_LINE_X_DATA, 0, 0, &bltXVectorOption},
  293.     {TK_CONFIG_CUSTOM, "-ydata", "elemYdata", "Ydata",
  294.     DEF_LINE_Y_DATA, 0, 0, &bltYVectorOption},
  295.     {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
  296. };
  297.  
  298.  
  299.  
  300. /* ----------------------------------------------------------------------
  301.  * Custom option parse and print procedures
  302.  * ----------------------------------------------------------------------
  303.  */
  304.  
  305. /*
  306.  *----------------------------------------------------------------------
  307.  *
  308.  * ParseSymbolType --
  309.  *
  310.  *    Convert the string representation of a line style or symbol name
  311.  *    into its numeric form.
  312.  *
  313.  * Results:
  314.  *    The return value is a standard Tcl result.  The symbol type is
  315.  *    written into the widget record.
  316.  *
  317.  *----------------------------------------------------------------------
  318.  */
  319. /*ARGSUSED*/
  320. static int
  321. ParseSymbolType(clientData, interp, tkwin, value, widgRec, offset)
  322.     ClientData clientData;    /* not used */
  323.     Tcl_Interp *interp;        /* Interpreter to send results back to */
  324.     Tk_Window tkwin;        /* not used */
  325.     char *value;        /* String representing symbol type */
  326.     char *widgRec;        /* Element information record */
  327.     int offset;            /* Offset of symbol type field in record */
  328. {
  329.     int *symbolPtr = (int *)(widgRec + offset);
  330.     int index;
  331.  
  332.     index = Blt_GetTokenIndex(symbolTokens, value, 1);
  333.     if (index < 0) {
  334.     Tcl_AppendResult(interp, "bad symbol name \"", value, "\"",
  335.         (char *)NULL);
  336.     return TCL_ERROR;
  337.     }
  338.     *symbolPtr = index;
  339.     return TCL_OK;
  340. }
  341.  
  342. /*
  343.  *----------------------------------------------------------------------
  344.  *
  345.  * PrintSymbolType --
  346.  *
  347.  *    Convert the symbol value into a string.
  348.  *
  349.  * Results:
  350.  *    The string representing the symbol type or line style is returned.
  351.  *
  352.  *----------------------------------------------------------------------
  353.  */
  354. /*ARGSUSED*/
  355. static char *
  356. PrintSymbolType(clientData, tkwin, widgRec, offset, freeProcPtr)
  357.     ClientData clientData;    /* not used */
  358.     Tk_Window tkwin;        /* not used */
  359.     char *widgRec;        /* Element information record */
  360.     int offset;            /* Offset of symbol type field in record */
  361.     Tcl_FreeProc **freeProcPtr;    /* not used */
  362. {
  363.     int symbol = *(int *)(widgRec + offset);
  364.  
  365.     return (symbolTokens[symbol]);
  366. }
  367.  
  368. /*
  369.  *----------------------------------------------------------------------
  370.  *
  371.  * ParseTrace --
  372.  *
  373.  *    Convert the string representation of a line style or symbol name
  374.  *    into its numeric form.
  375.  *
  376.  * Results:
  377.  *    The return value is a standard Tcl result.  The symbol type is
  378.  *    written into the widget record.
  379.  *
  380.  *----------------------------------------------------------------------
  381.  */
  382. /*ARGSUSED*/
  383. static int
  384. ParseTrace(clientData, interp, tkwin, value, widgRec, offset)
  385.     ClientData clientData;    /* not used */
  386.     Tcl_Interp *interp;        /* Interpreter to send results back to */
  387.     Tk_Window tkwin;        /* not used */
  388.     char *value;        /* String representing symbol type */
  389.     char *widgRec;        /* Element information record */
  390.     int offset;            /* Offset of symbol type field in record */
  391. {
  392.     int *valuePtr = (int *)(widgRec + offset);
  393.     int index;
  394.  
  395.     index = Blt_GetTokenIndex(traceTokens, value, 0);
  396.     if (index < 0) {
  397.     Tcl_AppendResult(interp, "bad trace value \"", value,
  398.         "\" : should be \"increasing\", \"decreasing\", or \"both\"",
  399.         (char *)NULL);
  400.     return TCL_ERROR;
  401.     }
  402.     *valuePtr = index;
  403.     return TCL_OK;
  404. }
  405.  
  406. /*
  407.  *----------------------------------------------------------------------
  408.  *
  409.  * PrintTrace --
  410.  *
  411.  *    Convert the symbol value into a string.
  412.  *
  413.  * Results:
  414.  *    The string representing the symbol type or line style is returned.
  415.  *
  416.  *----------------------------------------------------------------------
  417.  */
  418. /*ARGSUSED*/
  419. static char *
  420. PrintTrace(clientData, tkwin, widgRec, offset, freeProcPtr)
  421.     ClientData clientData;    /* not used */
  422.     Tk_Window tkwin;        /* not used */
  423.     char *widgRec;        /* Element information record */
  424.     int offset;            /* Offset of symbol type field in record */
  425.     Tcl_FreeProc **freeProcPtr;    /* not used */
  426. {
  427.     int value = *(int *)(widgRec + offset);
  428.  
  429.     return (traceTokens[value]);
  430. }
  431.  
  432. /*
  433.  *----------------------------------------------------------------------
  434.  *
  435.  * ConfigureLine --
  436.  *
  437.  *    Sets up the appropriate configuration parameters in the GC.
  438.  *      It is assumed the parameters have been previously set by
  439.  *    a call to Tk_ConfigureWidget.
  440.  *
  441.  * Results:
  442.  *    The return value is a standard Tcl result.  If TCL_ERROR is
  443.  *    returned, then interp->result contains an error message.
  444.  *
  445.  * Side effects:
  446.  *    Configuration information such as line width, line style, color
  447.  *    etc. get set in a new GC.
  448.  *
  449.  *----------------------------------------------------------------------
  450.  */
  451. /*ARGSUSED*/
  452. static int
  453. ConfigureLine(graphPtr, elemPtr)
  454.     Graph *graphPtr;
  455.     Element *elemPtr;
  456. {
  457.     Line *linePtr = (Line *)elemPtr;
  458.     unsigned long gcMask;
  459.     GC newGC;
  460.     XGCValues gcValues;
  461.  
  462.     /* Borders of symbols: need foreground only */
  463.  
  464.     gcMask = (GCLineWidth | GCForeground);
  465.     gcValues.foreground = linePtr->normalBg->pixel;
  466.     gcValues.line_width = linePtr->borderWidth;
  467.     newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
  468.     if (linePtr->normalBorderGC != NULL) {
  469.     Tk_FreeGC(graphPtr->display, linePtr->normalBorderGC);
  470.     }
  471.     linePtr->normalBorderGC = newGC;
  472.  
  473.     gcValues.foreground = linePtr->activeBg->pixel;
  474.     newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
  475.     if (linePtr->activeBorderGC != NULL) {
  476.     Tk_FreeGC(graphPtr->display, linePtr->activeBorderGC);
  477.     }
  478.     linePtr->activeBorderGC = newGC;
  479.  
  480.     /* Fills for symbols: need reversed foreground and background */
  481.  
  482.     gcMask |= GCBackground;
  483.     gcValues.background = linePtr->normalBg->pixel;
  484.     gcValues.foreground = linePtr->normalFg->pixel;
  485.     newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
  486.     if (linePtr->normalFillGC != NULL) {
  487.     Tk_FreeGC(graphPtr->display, linePtr->normalFillGC);
  488.     }
  489.     linePtr->normalFillGC = newGC;
  490.  
  491.     gcValues.background = linePtr->activeBg->pixel;
  492.     gcValues.foreground = linePtr->activeFg->pixel;
  493.     newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
  494.     if (linePtr->activeFillGC != NULL) {
  495.     Tk_FreeGC(graphPtr->display, linePtr->activeFillGC);
  496.     }
  497.     linePtr->activeFillGC = newGC;
  498.  
  499.     /* Lines */
  500.  
  501.     gcMask |= (GCLineStyle | GCCapStyle | GCJoinStyle);
  502.     gcValues.cap_style = CapButt;
  503.     gcValues.join_style = JoinRound;
  504.     gcValues.line_style = LineSolid;
  505.     gcValues.line_width = linePtr->lineWidth;
  506.     gcValues.background = linePtr->normalBg->pixel;
  507.     gcValues.foreground = linePtr->normalFg->pixel;
  508.     if (linePtr->dashes > 0) {
  509.     gcValues.dash_offset = 0;
  510.     gcValues.line_style = LineDoubleDash;
  511.     gcValues.dashes = linePtr->dashes;
  512.     gcMask |= (GCDashList | GCDashOffset);
  513.     }
  514.     newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
  515.     if (linePtr->normalLineGC != NULL) {
  516.     Tk_FreeGC(graphPtr->display, linePtr->normalLineGC);
  517.     }
  518.     linePtr->normalLineGC = newGC;
  519.  
  520.     gcValues.background = linePtr->activeBg->pixel;
  521.     gcValues.foreground = linePtr->activeFg->pixel;
  522.     gcValues.line_width = linePtr->activeLineWidth;
  523.     newGC = Tk_GetGC(graphPtr->tkwin, gcMask, &gcValues);
  524.     if (linePtr->activeLineGC != NULL) {
  525.     Tk_FreeGC(graphPtr->display, linePtr->activeLineGC);
  526.     }
  527.     linePtr->activeLineGC = newGC;
  528.     return TCL_OK;
  529. }
  530.  
  531. /*
  532.  *----------------------------------------------------------------------
  533.  *
  534.  * GetLineLimits --
  535.  *
  536.  *    Returns the limits of the line element
  537.  *
  538.  * Results:
  539.  *    None.
  540.  *
  541.  *----------------------------------------------------------------------
  542.  */
  543. /*ARGSUSED*/
  544. static int
  545. GetLineLimits(graphPtr, elemPtr, axisPtr, minPtr, maxPtr)
  546.     Graph *graphPtr;        /* Graph widget record */
  547.     Element *elemPtr;
  548.     GraphAxis *axisPtr;        /* Axis information */
  549.     double *minPtr, *maxPtr;
  550. {
  551.     Line *linePtr = (Line *)elemPtr;
  552.     int numPoints;
  553.  
  554.     *minPtr = Blt_posInfinity, *maxPtr = Blt_negInfinity;
  555.     numPoints = BLT_MIN(linePtr->x.length, linePtr->y.length);
  556.  
  557.     /* Verify the element uses this axis */
  558.     if (!(elemPtr->axisFlags & AXIS_MASK(axisPtr))) {
  559.     return 0;
  560.     }
  561.     if (numPoints > 0) {
  562.     if (X_AXIS(axisPtr)) {
  563.         *minPtr = (axisPtr->logScale) ? linePtr->x.logMin : linePtr->x.min;
  564.         *maxPtr = linePtr->x.max;
  565.     } else {
  566.         *minPtr = (axisPtr->logScale) ? linePtr->y.logMin : linePtr->y.min;
  567.         *maxPtr = linePtr->y.max;
  568.     }
  569.     }
  570.     return (numPoints);
  571. }
  572.  
  573. /*
  574.  *----------------------------------------------------------------------
  575.  *
  576.  * ClosestLine --
  577.  *
  578.  *    Find the distance of the data point in the element closest to
  579.  *    the window coordinates point specified.
  580.  *
  581.  * Results:
  582.  *    Returns the distance of the closest point.  In addition,
  583.  *    indexPtr is set to position of coordinate and the list of data
  584.  *    points.  Index is -1 if the point does not fail within the
  585.  *    prescribed range.
  586.  *
  587.  *----------------------------------------------------------------------
  588.  */
  589. static int
  590. ClosestLine(graphPtr, elemPtr, winX, winY, closePtr)
  591.     Graph *graphPtr;        /* Graph widget record */
  592.     Element *elemPtr;        /* Element to examine */
  593.     int winX, winY;        /* Window coordinates of point on screen */
  594.     ClosestPoint *closePtr;    /* Info about closest point in element */
  595. {
  596.     int length;
  597.     Line *linePtr = (Line *)elemPtr;
  598.     unsigned int dist, maxDist, minDist;
  599.     int delta;
  600.     unsigned int deltaX, deltaY;
  601.     double realDist;
  602.     register int i;
  603.     int index;
  604.  
  605.     length = linePtr->numPoints;
  606.     maxDist = graphPtr->halo * graphPtr->halo;
  607.     minDist = maxDist + 1;
  608.     index = -1;
  609.     for (i = 0; i < length; i++) {
  610.     delta = winX - linePtr->pointArr[i].x;
  611.     deltaX = BLT_ABS(delta);
  612.     delta = winY - linePtr->pointArr[i].y;
  613.     deltaY = BLT_ABS(delta);
  614.     if ((deltaX > graphPtr->halo) || (deltaY > graphPtr->halo)) {
  615.         continue;
  616.     }
  617.     dist = deltaX * deltaX + deltaY * deltaY;
  618.     if (dist < minDist) {
  619.         index = i;
  620.         minDist = dist;
  621.     }
  622.     }
  623.     if (minDist > maxDist) {
  624.     return 0;
  625.     }
  626.     realDist = sqrt((double)minDist);
  627.     if (realDist > (double)graphPtr->halo) {
  628.     return 0;
  629.     }
  630.     closePtr->elemPtr = elemPtr;
  631.     closePtr->index = index;
  632.     closePtr->x = linePtr->x.data[index];
  633.     closePtr->y = linePtr->y.data[index];
  634.     closePtr->dist = realDist;
  635.     return (realDist);
  636. }
  637.  
  638. /*
  639.  *----------------------------------------------------------------------
  640.  *
  641.  * LayoutLine --
  642.  *
  643.  *    Calculates the actual window coordinates of the line element.
  644.  *    The window coordinates are saved in an allocated point array.
  645.  *
  646.  * Results:
  647.  *    None.
  648.  *
  649.  * Side effects:
  650.  *    Memory is (re)allocated for the point array.
  651.  *
  652.  *----------------------------------------------------------------------
  653.  */
  654. static void
  655. LayoutLine(graphPtr, elemPtr)
  656.     Graph *graphPtr;        /* Graph widget record */
  657.     Element *elemPtr;        /* Element component record */
  658. {
  659.     Line *linePtr = (Line *)elemPtr;
  660.     XPoint *pointArr;
  661.     unsigned int numPoints;
  662.     int x, lastX;
  663.     int total, numSegments;
  664.     double avgSize;
  665.     register int i;
  666.     CurveSegment *segArr;
  667.     int needSegments;
  668.  
  669.     numPoints = BLT_MIN(linePtr->x.length, linePtr->y.length);
  670.     if (numPoints < 1) {
  671.     linePtr->numPoints = linePtr->numSegments = 0;
  672.     return;
  673.     }
  674.     pointArr = (XPoint *)malloc(numPoints * sizeof(XPoint));
  675.     if (pointArr == NULL) {
  676.     return;            /* Can't allocate point array */
  677.     }
  678.     /*
  679.      * We need to determine is line segments exist only if
  680.      *
  681.      * 1) retracing is not allowed, and
  682.      *
  683.      * 2) we need to draw element lines (either because the symbol
  684.      *    type is "line" or the line width is greater than zero,
  685.      *      which means to add a line in addition to the symbol).
  686.      */
  687.     needSegments = ((linePtr->trace != TRACE_BOTH) &&
  688.     ((linePtr->lineWidth > 0) || (linePtr->symbol == LINE_SYMBOL)));
  689.     /*
  690.      * Transform and store the coordinates into an array window
  691.      * points.  In addition, make a quick count of line segments.
  692.      */
  693.     lastX = 0;            /* suppress compiler warning */
  694.     total = numSegments = 0;
  695.     for (i = 0; i < numPoints; i++) {
  696.     pointArr[i] = Blt_TransformPt(graphPtr, linePtr->x.data[i],
  697.         linePtr->y.data[i], linePtr->axisFlags);
  698.     x = pointArr[i].x;
  699.     if ((needSegments) && (total > 0) &&
  700.         BROKEN_TRACE(linePtr->trace, x, lastX)) {
  701.         numSegments++;
  702.         total = 0;
  703.     }
  704.     total++;
  705.     lastX = x;
  706.     }
  707.     if (total > 0) {
  708.     numSegments++;
  709.     }
  710.     /* Create an array of line segment information  */
  711.     segArr = (CurveSegment *) malloc(sizeof(CurveSegment) * numSegments);
  712.     if (segArr == NULL) {
  713.     return;
  714.     }
  715.     if (!needSegments) {
  716.     segArr[0].pointPtr = pointArr;
  717.     segArr[0].numPoints = numPoints;
  718.     } else {
  719.     int count;
  720.  
  721.     lastX = 0;        /* suppress compiler warning */
  722.     total = count = 0;
  723.     for (i = 0; i < numPoints; i++) {
  724.         x = pointArr[i].x;
  725.         if ((total > 0) && (BROKEN_TRACE(linePtr->trace, x, lastX))) {
  726.         segArr[count].pointPtr = pointArr + (i - total);
  727.         segArr[count].numPoints = total;
  728.         count++;
  729.         total = 0;
  730.         }
  731.         total++;
  732.         lastX = x;
  733.     }
  734.     if (total > 0) {
  735.         segArr[count].pointPtr = pointArr + (i - total);
  736.         segArr[count].numPoints = total;
  737.         count++;
  738.     }
  739.     }
  740.     if (linePtr->pointArr != NULL) {
  741.     free((char *)linePtr->pointArr);
  742.     }
  743.     linePtr->pointArr = pointArr;
  744.     linePtr->numPoints = numPoints;
  745.     if (linePtr->segArr != NULL) {
  746.     free((char *)linePtr->segArr);
  747.     }
  748.     linePtr->segArr = segArr;
  749.     linePtr->numSegments = numSegments;
  750.  
  751.     /* Make the symbol size odd so that its center is a single pixel. */
  752.     linePtr->symbolSize |= 0x01;
  753.     avgSize = graphPtr->avgSymSize * linePtr->symbolScale;
  754.     linePtr->symbolSize = BLT_RND(avgSize);
  755. }
  756.  
  757. /*
  758.  * -----------------------------------------------------------------
  759.  *
  760.  * SymbolDrawInfo --
  761.  *
  762.  *     Initialize a structure containing information about how to
  763.  *    draw the a symbol at a particular size.  For example, we
  764.  *    precalculate the offsets draw the symbol, rather than
  765.  *    computing them at each data point. Some information is
  766.  *    stored in this structure to save passing it in to each call
  767.  *    of DrawLineSymbol.
  768.  *
  769.  * Results:
  770.  *    Returns a pointer to a static symbol information structure.
  771.  *
  772.  * Problems:
  773.  *    Most notable is the round-off errors generated when
  774.  *    calculating the centered position of the symbol.
  775.  *
  776.  * -----------------------------------------------------------------
  777.  */
  778. static SymbolInfo *
  779. SymbolDrawInfo(graphPtr, linePtr, size, active)
  780.     Graph *graphPtr;        /* Graph widget record */
  781.     Line *linePtr;        /* Line element information */
  782.     int size;            /* Size of element */
  783.     int active;            /* If non-zero, set to draw active element */
  784. {
  785.     static SymbolInfo s;
  786.     int delta;
  787.  
  788.     s.display = graphPtr->display;
  789.     s.canvas = graphPtr->canvas;
  790.     s.radius = (size / 2);
  791.     s.size = size;
  792.     s.type = linePtr->symbol;
  793.     s.needBorder = (linePtr->borderWidth > 0);
  794.  
  795.     switch (s.type) {
  796.     case CROSS_SYMBOL:
  797.     case PLUS_SYMBOL:
  798.  
  799.     delta = (size / 6);
  800.  
  801.     /*
  802.      *
  803.      *          2   3    The plus/cross symbol is a closed polygon
  804.      *            of 12 points. The diagram to the left
  805.      *    0,12  1   4    5    represents the positions of the points
  806.      *           x,y    which are computed below. The extra
  807.      *     11  10   7    6    (thirteenth) point connects the first and
  808.      *            last points.
  809.      *          9   8
  810.      */
  811.  
  812.     s.offset[0].x = s.offset[11].x = s.offset[12].x = -s.radius;
  813.     s.offset[2].x = s.offset[1].x = s.offset[10].x = s.offset[9].x =
  814.         -delta;
  815.     s.offset[3].x = s.offset[4].x = s.offset[7].x = s.offset[8].x =
  816.         delta;
  817.     s.offset[5].x = s.offset[6].x = s.radius;
  818.     s.offset[2].y = s.offset[3].y = -s.radius;
  819.     s.offset[0].y = s.offset[1].y = s.offset[4].y = s.offset[5].y =
  820.         s.offset[12].y = -delta;
  821.     s.offset[11].y = s.offset[10].y = s.offset[7].y = s.offset[6].y =
  822.         delta;
  823.     s.offset[9].y = s.offset[8].y = s.radius;
  824.     if (linePtr->symbol == CROSS_SYMBOL) {
  825.         register int i;
  826.         register double dx, dy, temp;
  827.  
  828.         /* For the cross symbol, rotate the points by 45 degrees. */
  829.         for (i = 0; i < 12; i++) {
  830.         dx = (double)(s.offset[i].x) * M_SQRT1_2;
  831.         dy = (double)(s.offset[i].y) * M_SQRT1_2;
  832.         temp = dx - dy;
  833.         s.offset[i].x = BLT_RND(temp);
  834.         temp = dx + dy;
  835.         s.offset[i].y = BLT_RND(temp);
  836.         }
  837.         s.offset[12] = s.offset[0];
  838.     }
  839.     break;
  840.  
  841.     case DIAMOND_SYMBOL:
  842.  
  843.     /*
  844.      *
  845.      *                     The plus symbol is a closed polygon
  846.      *          1        of 4 points. The diagram to the left
  847.      *                      represents the positions of the points
  848.      *       0,4 x,y  2    which are computed below. The extra
  849.      *                 (fifth) point connects the first and
  850.      *          3        last points.
  851.      *
  852.      */
  853.  
  854.     s.offset[0].y = s.offset[4].y = s.offset[2].y = s.offset[1].x =
  855.         s.offset[3].x = 0;
  856.     s.offset[1].y = s.offset[4].x = s.offset[0].x = -s.radius;
  857.     s.offset[3].y = s.offset[2].x = s.radius;
  858.     break;
  859.  
  860.     case SPLUS_SYMBOL:
  861.     case SCROSS_SYMBOL:
  862.     s.radius = size / 2;
  863.     s.offset[0].y = s.offset[1].y = s.offset[2].x = s.offset[3].x = 0;
  864.     s.offset[0].x = s.offset[2].y = -s.radius;
  865.     s.offset[1].x = s.offset[3].y = s.radius;
  866.     /* Rotate the 4 points 45 degrees for a cross */
  867.     if (s.type == SCROSS_SYMBOL) {
  868.         register int i;
  869.         register double dx, dy, temp;
  870.  
  871.         for (i = 0; i < 4; i++) {
  872.         dx = (double)(s.offset[i].x) * M_SQRT1_2;
  873.         dy = (double)(s.offset[i].y) * M_SQRT1_2;
  874.         temp = dx - dy;
  875.         s.offset[i].x = BLT_RND(temp);
  876.         temp = dx + dy;
  877.         s.offset[i].y = BLT_RND(temp);
  878.         }
  879.     }
  880.     break;
  881.  
  882.     case SQUARE_SYMBOL:
  883.     s.size = (int)ceil(size * M_SQRT1_2);
  884.     s.radius = size / 2;
  885.     break;
  886.  
  887.     case CIRCLE_SYMBOL:
  888.     s.size--;
  889.     break;
  890.  
  891.     case LINE_SYMBOL:
  892.     break;
  893.     }
  894.  
  895.     /* Set the correct GCs, depending if the element is active  */
  896.     if (active) {
  897.     s.borderGC = linePtr->activeBorderGC;
  898.     s.lineGC = linePtr->activeLineGC;
  899.     s.fillGC = linePtr->activeFillGC;
  900.     } else {
  901.     s.borderGC = linePtr->normalBorderGC;
  902.     s.lineGC = linePtr->normalLineGC;
  903.     s.fillGC = linePtr->normalFillGC;
  904.     }
  905.     return (&s);
  906. }
  907.  
  908. /*
  909.  * -----------------------------------------------------------------
  910.  *
  911.  * DrawSymbol --
  912.  *
  913.  *     Draws the symbol (as indicated by the symbol information
  914.  *    structure) centered at the given x,y coordinate.
  915.  *
  916.  * Results:
  917.  *    None.
  918.  *
  919.  * -----------------------------------------------------------------
  920.  */
  921. static void
  922. DrawSymbol(x, y, infoPtr)
  923.     int x, y;            /* x,y coordinates of center of symbol */
  924.     SymbolInfo *infoPtr;    /* Information how to draw the symbol */
  925. {
  926.     XPoint points[13];
  927.     XSegment segments[2];
  928.     register int n;
  929.  
  930.     switch (infoPtr->type) {
  931.     case LINE_SYMBOL:
  932.     /*
  933.      * Draw an extra line offset by one pixel from the previous to
  934.      * give a thicker appearance
  935.      */
  936.     XDrawLine(infoPtr->display, infoPtr->canvas, infoPtr->lineGC,
  937.         x - infoPtr->radius, y, x + infoPtr->radius, y);
  938.     XDrawLine(infoPtr->display, infoPtr->canvas, infoPtr->lineGC,
  939.         x - infoPtr->radius, y + 1, x + infoPtr->radius, y + 1);
  940.     break;
  941.  
  942.     case PLUS_SYMBOL:
  943.     case CROSS_SYMBOL:
  944.     for (n = 0; n < 13; n++) {
  945.         points[n].x = infoPtr->offset[n].x + x;
  946.         points[n].y = infoPtr->offset[n].y + y;
  947.     }
  948.     XFillPolygon(infoPtr->display, infoPtr->canvas, infoPtr->fillGC,
  949.         points, 13, Complex, CoordModeOrigin);
  950.     if (infoPtr->needBorder) {
  951.         XDrawLines(infoPtr->display, infoPtr->canvas, infoPtr->borderGC,
  952.         points, 13, CoordModeOrigin);
  953.     }
  954.     break;
  955.  
  956.     case SPLUS_SYMBOL:
  957.     case SCROSS_SYMBOL:
  958.     segments[0].x1 = infoPtr->offset[0].x + x;
  959.     segments[0].y1 = infoPtr->offset[0].y + y;
  960.     segments[0].x2 = infoPtr->offset[1].x + x;
  961.     segments[0].y2 = infoPtr->offset[1].y + y;
  962.     segments[1].x1 = infoPtr->offset[2].x + x;
  963.     segments[1].y1 = infoPtr->offset[2].y + y;
  964.     segments[1].x2 = infoPtr->offset[3].x + x;
  965.     segments[1].y2 = infoPtr->offset[3].y + y;
  966.     /* I'm not sure what attributes this symbol type should have.
  967.      * Right now I using the border GC instead of line or fill GC */
  968.     XDrawSegments(infoPtr->display, infoPtr->canvas, infoPtr->borderGC,
  969.         segments, 2);
  970.     break;
  971.  
  972.     case SQUARE_SYMBOL:
  973.     x -= infoPtr->radius, y -= infoPtr->radius;
  974.     XFillRectangle(infoPtr->display, infoPtr->canvas, infoPtr->fillGC,
  975.         x, y, infoPtr->size, infoPtr->size);
  976.     if (infoPtr->needBorder) {
  977.         XDrawRectangle(infoPtr->display, infoPtr->canvas,
  978.         infoPtr->borderGC, x, y, infoPtr->size, infoPtr->size);
  979.     }
  980.     break;
  981.  
  982.     case CIRCLE_SYMBOL:
  983.     x -= infoPtr->radius, y -= infoPtr->radius;
  984.     XFillArc(infoPtr->display, infoPtr->canvas, infoPtr->fillGC, x, y,
  985.         infoPtr->size, infoPtr->size, 0, 23040);
  986.     if (infoPtr->needBorder) {
  987.         XDrawArc(infoPtr->display, infoPtr->canvas, infoPtr->borderGC,
  988.         x, y, infoPtr->size, infoPtr->size, 0, 23040);
  989.     }
  990.     break;
  991.  
  992.     case DIAMOND_SYMBOL:
  993.     for (n = 0; n < 5; n++) {
  994.         points[n].x = infoPtr->offset[n].x + x;
  995.         points[n].y = infoPtr->offset[n].y + y;
  996.     }
  997.     XFillPolygon(infoPtr->display, infoPtr->canvas, infoPtr->fillGC,
  998.         points, 5, Convex, CoordModeOrigin);
  999.     if (infoPtr->needBorder) {
  1000.         XDrawLines(infoPtr->display, infoPtr->canvas, infoPtr->borderGC,
  1001.         points, 5, CoordModeOrigin);
  1002.     }
  1003.     break;
  1004.     }
  1005. }
  1006.  
  1007. /*
  1008.  * -----------------------------------------------------------------
  1009.  *
  1010.  * DrawSymbols --
  1011.  *
  1012.  *     Draw a symbol centered at each point given in the array of
  1013.  *    window coordinates (coordArr) based upon the element symbol
  1014.  *    type and size.
  1015.  *
  1016.  * Results:
  1017.  *    None.
  1018.  *
  1019.  * Problems:
  1020.  *    Most notable is the round-off errors generated when
  1021.  *    calculating the centered position of the symbol.
  1022.  *
  1023.  * -----------------------------------------------------------------
  1024.  */
  1025. static void
  1026. DrawSymbols(graphPtr, elemPtr, size, pointArr, numPoints, active)
  1027.     Graph *graphPtr;        /* Graph widget record */
  1028.     Element *elemPtr;        /* Line element information */
  1029.     int size;            /* Size of element */
  1030.     XPoint *pointArr;        /* Array of x,y coordinates for line */
  1031.     int numPoints;        /* Number of coordinates in array */
  1032.     int active;
  1033. {
  1034.     Line *linePtr = (Line *)elemPtr;
  1035.     SymbolInfo *infoPtr;
  1036.     register unsigned int i, index;
  1037.     unsigned int maxIndex;
  1038.     int useIndex;
  1039.  
  1040.     infoPtr = SymbolDrawInfo(graphPtr, linePtr, size, active);
  1041.     useIndex = ((active) && (linePtr->numActivePoints > 0));
  1042.     if (useIndex) {
  1043.     maxIndex = numPoints - 1;
  1044.     numPoints = linePtr->numActivePoints;
  1045.     }
  1046.     for (i = 0; i < numPoints; i++) {
  1047.     index = i;
  1048.     if (useIndex) {
  1049.         index = linePtr->activeArr[i];
  1050.         if (index > maxIndex) {
  1051.         continue;
  1052.         }
  1053.     }
  1054.     DrawSymbol(pointArr[index].x, pointArr[index].y, infoPtr);
  1055.     }
  1056. }
  1057.  
  1058. /*
  1059.  *----------------------------------------------------------------------
  1060.  *
  1061.  * DisplayLine --
  1062.  *
  1063.  *    Draws the connected line(s) representing the element. If the
  1064.  *    line is made up of non-line symbols and the line width parameter
  1065.  *    has been set (linewidth > 0), the element will also be drawn as
  1066.  *    a line (with the linewidth requested).  The line may consist of
  1067.  *    separate line segments.
  1068.  *
  1069.  * Results:
  1070.  *    None.
  1071.  *
  1072.  * Side effects:
  1073.  *    X drawing commands are output.
  1074.  *
  1075.  *----------------------------------------------------------------------
  1076.  */
  1077. static void
  1078. DisplayLine(graphPtr, elemPtr, active)
  1079.     Graph *graphPtr;        /* Graph widget record */
  1080.     Element *elemPtr;        /* Element to be drawn */
  1081.     int active;            /* Determines if line is drawn with normal
  1082.                  * or active foreground/background colors */
  1083. {
  1084.     Line *linePtr = (Line *)elemPtr;
  1085.     int needLine;
  1086.     GC lineGC;
  1087.  
  1088.     if (linePtr->numPoints < 1) {
  1089.     return;
  1090.     }
  1091.     if (active) {
  1092.     needLine = ((linePtr->numActivePoints == 0) &&
  1093.         ((linePtr->activeLineWidth > 0) ||
  1094.         (linePtr->symbol == LINE_SYMBOL)));
  1095.     lineGC = linePtr->activeLineGC;
  1096.     } else {
  1097.     /*
  1098.      * Draw lines if symbol is "line" or linewidth is greater than 0
  1099.      */
  1100.     needLine = ((linePtr->lineWidth > 0) ||
  1101.         (linePtr->symbol == LINE_SYMBOL));
  1102.     lineGC = linePtr->normalLineGC;
  1103.     }
  1104.     if (needLine) {
  1105.     register int i;
  1106.  
  1107.     for (i = 0; i < linePtr->numSegments; i++) {
  1108.         XDrawLines(graphPtr->display, graphPtr->canvas, lineGC,
  1109.         linePtr->segArr[i].pointPtr, linePtr->segArr[i].numPoints,
  1110.         CoordModeOrigin);
  1111.     }
  1112.     }
  1113.     /* Draw non-line symbols */
  1114.     if (linePtr->symbol != LINE_SYMBOL) {
  1115.     DrawSymbols(graphPtr, (Element *)linePtr, linePtr->symbolSize,
  1116.         linePtr->pointArr, linePtr->numPoints, active);
  1117.     }
  1118. }
  1119.  
  1120. /*
  1121.  * -----------------------------------------------------------------
  1122.  *
  1123.  * SymbolPrintInfo --
  1124.  *
  1125.  *     Draw a symbol centered at the given x,y window coordinate
  1126.  *    based upon the element symbol type and size.
  1127.  *
  1128.  * Results:
  1129.  *    None.
  1130.  *
  1131.  * Problems:
  1132.  *    Most notable is the round-off errors generated when
  1133.  *    calculating the centered position of the symbol.
  1134.  * -----------------------------------------------------------------
  1135.  */
  1136. static void
  1137. SymbolPrintInfo(graphPtr, linePtr, active)
  1138.     Graph *graphPtr;
  1139.     Line *linePtr;
  1140.     int active;
  1141. {
  1142.     XColor *bgColorPtr, *fgColorPtr;
  1143.  
  1144.     /* Set line and foreground attributes */
  1145.     if (active) {
  1146.     fgColorPtr = linePtr->activeFg;
  1147.     bgColorPtr = linePtr->activeBg;
  1148.     } else {
  1149.     fgColorPtr = linePtr->normalFg;
  1150.     bgColorPtr = linePtr->normalBg;
  1151.     }
  1152.     if ((linePtr->symbol == SPLUS_SYMBOL) ||
  1153.     (linePtr->symbol == SCROSS_SYMBOL)) {
  1154.     Blt_ForegroundToPostScript(graphPtr, bgColorPtr);
  1155.     } else {
  1156.     Blt_ForegroundToPostScript(graphPtr, fgColorPtr);
  1157.     }
  1158.     if (linePtr->symbol == LINE_SYMBOL) {
  1159.     Blt_LineWidthToPostScript(graphPtr, linePtr->lineWidth + 2);
  1160.     Blt_LineDashesToPostScript(graphPtr, linePtr->dashes);
  1161.     } else {
  1162.     Blt_LineWidthToPostScript(graphPtr, linePtr->lineWidth);
  1163.     Blt_LineDashesToPostScript(graphPtr, 0);
  1164.     }
  1165.     Tcl_AppendResult(graphPtr->interp, "/BgColorProc {\n   ", (char *)NULL);
  1166.     Blt_BackgroundToPostScript(graphPtr, bgColorPtr);
  1167.     Tcl_AppendResult(graphPtr->interp, "} def\n", (char *)NULL);
  1168.  
  1169.     if ((linePtr->symbol != LINE_SYMBOL) &&
  1170.     (linePtr->borderWidth > 0)) {
  1171.     Tcl_AppendResult(graphPtr->interp, "/BorderProc {\n  gsave\n",
  1172.         (char *)NULL);
  1173.     Blt_BackgroundToPostScript(graphPtr, bgColorPtr);
  1174.     Blt_LineWidthToPostScript(graphPtr, linePtr->borderWidth);
  1175.     Tcl_AppendResult(graphPtr->interp,
  1176.         "    stroke grestore } def\n", (char *)NULL);
  1177.     } else {
  1178.     Tcl_AppendResult(graphPtr->interp, "/BorderProc {} def\n",
  1179.         (char *)NULL);
  1180.     }
  1181. }
  1182.  
  1183. /*
  1184.  * -----------------------------------------------------------------
  1185.  *
  1186.  * PrintSymbols --
  1187.  *
  1188.  *     Draw a symbol centered at the given x,y window coordinate
  1189.  *    based upon the element symbol type and size.
  1190.  *
  1191.  * Results:
  1192.  *    None.
  1193.  *
  1194.  * Problems:
  1195.  *    Most notable is the round-off errors generated when
  1196.  *    calculating the centered position of the symbol.
  1197.  * -----------------------------------------------------------------
  1198.  */
  1199. static void
  1200. PrintSymbols(graphPtr, elemPtr, size, pointArr, numPoints, active)
  1201.     Graph *graphPtr;
  1202.     Element *elemPtr;
  1203.     int size;
  1204.     XPoint *pointArr;
  1205.     int numPoints;
  1206.     int active;
  1207. {
  1208.     Line *linePtr = (Line *)elemPtr;
  1209.     double symbolSize;
  1210.     register int i;
  1211.     int useIndex;
  1212.     unsigned int index, maxIndex;
  1213.  
  1214.     SymbolPrintInfo(graphPtr, linePtr, active);
  1215.     symbolSize = (double)size;
  1216.     if ((elemPtr->symbol == SQUARE_SYMBOL) ||
  1217.     (elemPtr->symbol == DIAMOND_SYMBOL)) {
  1218.     /* Adjust square and diamond symbol sizes */
  1219.     symbolSize = ((double)size * M_SQRT1_2) - 1;
  1220.     }
  1221.     useIndex = ((active) && (linePtr->numActivePoints > 0));
  1222.     if (useIndex) {
  1223.     maxIndex = numPoints - 1;
  1224.     numPoints = linePtr->numActivePoints;
  1225.     }
  1226.     for (i = 0; i < numPoints; i++) {
  1227.     index = i;
  1228.     if (useIndex) {
  1229.         index = linePtr->activeArr[i];
  1230.         if (index > maxIndex) {
  1231.         continue;
  1232.         }
  1233.     }
  1234.     sprintf(graphPtr->scratchPtr, "%d %d %g %.2s\n",
  1235.         pointArr[index].x, pointArr[index].y, symbolSize,
  1236.         symbolTokens[linePtr->symbol]);
  1237.     Tcl_AppendResult(graphPtr->interp, graphPtr->scratchPtr, (char *)NULL);
  1238.     }
  1239. }
  1240.  
  1241. /*
  1242.  *----------------------------------------------------------------------
  1243.  *
  1244.  * PrintLine --
  1245.  *
  1246.  *    Similar to the DrawLine procedure, prints PostScript related
  1247.  *    commands to form the connected line(s) representing the element.
  1248.  *
  1249.  * Results:
  1250.  *    None.
  1251.  *
  1252.  * Side effects:
  1253.  *    PostScript pen width, dashes, and color settings are changed.
  1254.  *
  1255.  *----------------------------------------------------------------------
  1256.  */
  1257. static void
  1258. PrintLine(graphPtr, elemPtr, active)
  1259.     Graph *graphPtr;
  1260.     Element *elemPtr;
  1261.     int active;
  1262. {
  1263.     Line *linePtr = (Line *)elemPtr;
  1264.     XColor *bgColorPtr, *fgColorPtr;
  1265.     int needLine;
  1266.     int lineWidth;
  1267.  
  1268.     if (linePtr->numPoints < 1) {
  1269.     return;
  1270.     }
  1271.     if (active) {
  1272.     needLine = ((linePtr->numActivePoints == 0) &&
  1273.         ((linePtr->activeLineWidth > 0) ||
  1274.         (linePtr->symbol == LINE_SYMBOL)));
  1275.     fgColorPtr = linePtr->activeFg;
  1276.     bgColorPtr = linePtr->activeBg;
  1277.     lineWidth = linePtr->activeLineWidth;
  1278.     } else {
  1279.     needLine =
  1280.         ((linePtr->lineWidth > 0) || (linePtr->symbol == LINE_SYMBOL));
  1281.     fgColorPtr = linePtr->normalFg;
  1282.     bgColorPtr = linePtr->normalBg;
  1283.     lineWidth = linePtr->lineWidth;
  1284.     }
  1285.  
  1286.     /* Set line and foreground attributes */
  1287.     Blt_ForegroundToPostScript(graphPtr, fgColorPtr);
  1288.  
  1289.     if (linePtr->dashes > 0) {
  1290.     Blt_LineDashesToPostScript(graphPtr, linePtr->dashes);
  1291.     Tcl_AppendResult(graphPtr->interp, "/DashesProc {\ngsave\n",
  1292.         (char *)NULL);
  1293.     Blt_BackgroundToPostScript(graphPtr, bgColorPtr);
  1294.     Blt_LineDashesToPostScript(graphPtr, 0);
  1295.     Tcl_AppendResult(graphPtr->interp, "stroke grestore\n} def\n",
  1296.         (char *)NULL);
  1297.     } else {
  1298.     Tcl_AppendResult(graphPtr->interp, "/DashesProc {} def\n",
  1299.         (char *)NULL);
  1300.     }
  1301.     Blt_LineWidthToPostScript(graphPtr, lineWidth);
  1302.     if (needLine) {
  1303.     register int i;
  1304.  
  1305.     for (i = 0; i < linePtr->numSegments; i++) {
  1306.         Blt_PrintLine(graphPtr, linePtr->segArr[i].pointPtr,
  1307.         linePtr->segArr[i].numPoints);
  1308.     }
  1309.     }
  1310.     /* Draw non-line symbols */
  1311.  
  1312.     if (linePtr->symbol != LINE_SYMBOL) {
  1313.     (*linePtr->printSymbolsProc) (graphPtr, (Element *)linePtr,
  1314.         linePtr->symbolSize, linePtr->pointArr, linePtr->numPoints,
  1315.         active);
  1316.     }
  1317. }
  1318.  
  1319. /*
  1320.  *----------------------------------------------------------------------
  1321.  *
  1322.  * DestroyLine --
  1323.  *
  1324.  *    Release memory and resources allocated for the line element.
  1325.  *
  1326.  * Results:
  1327.  *    None.
  1328.  *
  1329.  * Side effects:
  1330.  *    Everything associated with the line element is freed up.
  1331.  *
  1332.  *----------------------------------------------------------------------
  1333.  */
  1334. static void
  1335. DestroyLine(graphPtr, elemPtr)
  1336.     Graph *graphPtr;
  1337.     Element *elemPtr;
  1338. {
  1339.     Line *linePtr = (Line *)elemPtr;
  1340.  
  1341.     Tk_FreeOptions(linePtr->configSpecs, (char *)linePtr,
  1342.     graphPtr->display, 0);
  1343.  
  1344.     if (linePtr->normalBorderGC != NULL) {
  1345.     Tk_FreeGC(graphPtr->display, linePtr->normalBorderGC);
  1346.     }
  1347.     if (linePtr->normalFillGC != NULL) {
  1348.     Tk_FreeGC(graphPtr->display, linePtr->normalFillGC);
  1349.     }
  1350.     if (linePtr->normalLineGC != NULL) {
  1351.     Tk_FreeGC(graphPtr->display, linePtr->normalLineGC);
  1352.     }
  1353.     if (linePtr->activeBorderGC != NULL) {
  1354.     Tk_FreeGC(graphPtr->display, linePtr->activeBorderGC);
  1355.     }
  1356.     if (linePtr->activeFillGC != NULL) {
  1357.     Tk_FreeGC(graphPtr->display, linePtr->activeFillGC);
  1358.     }
  1359.     if (linePtr->activeLineGC != NULL) {
  1360.     Tk_FreeGC(graphPtr->display, linePtr->activeLineGC);
  1361.     }
  1362.     if (linePtr->pointArr != NULL) {
  1363.     free((char *)linePtr->pointArr);
  1364.     }
  1365.     if (linePtr->segArr != NULL) {
  1366.     free((char *)linePtr->segArr);
  1367.     }
  1368.     if (linePtr->x.data != NULL) {
  1369.     free((char *)linePtr->x.data);
  1370.     }
  1371.     if (linePtr->y.data != NULL) {
  1372.     free((char *)linePtr->y.data);
  1373.     }
  1374.     if (linePtr->activeArr != linePtr->staticArr) {
  1375.     free((char *)linePtr->activeArr);
  1376.     }
  1377.     free((char *)linePtr);
  1378. }
  1379.  
  1380. /*
  1381.  *----------------------------------------------------------------------
  1382.  *
  1383.  * Blt_LineElement --
  1384.  *
  1385.  *    Allocate memory and initialize methods for the new line element.
  1386.  *
  1387.  * Results:
  1388.  *    The pointer to the newly allocated element structure is returned.
  1389.  *
  1390.  * Side effects:
  1391.  *    Memory is allocated for the line element structure.
  1392.  *
  1393.  *----------------------------------------------------------------------
  1394.  */
  1395. Element *
  1396. Blt_LineElement()
  1397. {
  1398.     register Line *linePtr;
  1399.  
  1400.     linePtr = (Line *)calloc(1, sizeof(Line));
  1401.     if (linePtr == NULL) {
  1402.     return NULL;
  1403.     }
  1404.     linePtr->configSpecs = configSpecs;
  1405.     linePtr->configProc = ConfigureLine;
  1406.     linePtr->destroyProc = DestroyLine;
  1407.     linePtr->displayProc = DisplayLine;
  1408.     linePtr->limitsProc = GetLineLimits;
  1409.     linePtr->closestProc = ClosestLine;
  1410.     linePtr->layoutProc = LayoutLine;
  1411.     linePtr->printProc = PrintLine;
  1412.     linePtr->drawSymbolsProc = DrawSymbols;
  1413.     linePtr->printSymbolsProc = PrintSymbols;
  1414.     linePtr->borderWidth = 1;
  1415.     linePtr->activeLineWidth = linePtr->lineWidth = 1;
  1416.     linePtr->symbolScale = 1.0;
  1417.     linePtr->trace = TRACE_BOTH;
  1418.     linePtr->type = LINE_ELEM_TYPE;
  1419.     return ((Element *)linePtr);
  1420. }
  1421.